package com.sz.biz.common.base.service.impl;

import com.sz.biz.common.CommonAreaEntity;
import com.sz.biz.common.base.dto.*;
import com.sz.biz.common.base.entity.Area;
import com.sz.biz.common.base.entity.AreaCN;
import com.sz.biz.common.base.entity.Country;
import com.sz.biz.common.base.service.AreaService;
import com.sz.biz.common.constants.CommCodes;
import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.LanguageCode;
import com.sz.biz.common.customer.entity.CusUserAddress;
import com.sz.biz.common.customer.service.CustomerUserAddressService;
import com.sz.biz.logistics.base.dto.AddressModel;
import com.sz.biz.logistics.base.dto.Postcode;
import com.sz.biz.logistics.base.entity.Airport;
import com.sz.biz.logistics.base.entity.Port;
import com.sz.biz.logistics.base.service.AirportService;
import com.sz.biz.logistics.base.service.PortService;
import com.sz.biz.logistics.constants.RegionConstants;
import com.sz.common.base.dao.DaoSupport;
import com.sz.common.base.dao.Pagination;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.*;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.base.utils.EntityUtils;
import com.sz.common.core.service.PrincipalUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * Function: 地区AreaServiceImpl <br>
 * Author: penghui.zheng <br>
 * Date: 2016-11-09 13:41:00
 */
@Service("areaService")
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class AreaServiceImpl extends AbstractService implements AreaService {
    public static final String CHINESE = "[\u4e00-\u9fa5]";
    private static final int MAX_SIZE = 500;
    private static final String ROOT = "0";
    private static final String STRING_SPLIT = "/";
    @Autowired
    private CustomerUserAddressService customerUserAddress;
    @Autowired
    private PortService portService;//港口
    @Autowired
    private AirportService airportService;//空运
    @Resource(name = "daoSupport")
    private DaoSupport dao;

    @Override
    public List<CountryModel> findCountries(String q) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("q", q);
        pd.put("language", language);
        List<Country> countryList = dao.findForList("CountryMapper" + ".findArea", pd, Country.class);
        List<CountryModel> countries = new ArrayList<>();
        if (!CollectionUtils.isEmpty(countryList)) {
            countryList.forEach(country -> countries.add(new CountryModel(country.getFigureCode(), country.getName())));
        }
        return countries;
    }

    @Override
    public List<CountryModel> getCountrysByNameOrCode(String nameOrCode) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("language", language);
        pd.put("nameOrCode", nameOrCode);
        List<Country> countryList = dao.findForList("CountryMapper" + ".findCountryByNameOrCode", pd, Country.class);
        List<CountryModel> countries = new ArrayList<>();
        if (!CollectionUtils.isEmpty(countryList)) {
            countryList.forEach(country -> countries.add(new CountryModel(country.getFigureCode(), country.getName())));
        }
        return countries;
    }

    @Override
    public ResultDto findCountriesList(QueryParams params) {
        String language = PrincipalUtils.getLocalLanguage();
        params.setLanguage(language);
        ParamData pd = this.convertQueryParams(params);
        List<Country> countryList = dao.findForList("CountryMapper" + ".findCountryListPage", pd, Country.class);
        List<CountryModel> countries = new ArrayList<>();
        if (!CollectionUtils.isEmpty(countryList)) {
            countryList.forEach(country -> countries.add(new CountryModel(country.getFigureCode(), country.getName())));
        }
        QResultDto dto = new QResultDto();
        dto.setData(countries);
        dto.setPagination(pd.getPagination());
        return dto;
    }

    /**
     * 根据customerId和type查询国家
     *
     * @return
     */
    @Override
    public List<CountryModel> searchCountryByCustomerIdAndType(String q, int customerId, int type) {
        List<CusUserAddress> cusList = new ArrayList<>();
        List<CountryModel> countries = new ArrayList<>();
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("q", q);
        pd.put("language", language);
        if (q == null || "".equals(q)) {
            if (customerId > 0) {
                pd.put("customerId", customerId);
                pd.put("type", type);
                cusList = customerUserAddress.findCountryByCustomerIdAndType(customerId, type);
            }
        }
        List<Country> countryList = dao.findForList("CountryMapper" + ".findArea", pd, Country.class);
        if (cusList != null && cusList.size() > 0) {
            if (countryList != null && countryList.size() > 0) {
                for (CusUserAddress cusUserAddress : cusList) {
                    for (int i = 0; i < countryList.size(); i++) {
                        if (countryList.get(i).getFigureCode().equals(cusUserAddress.getCountry())) {
                            countryList.remove(i);
                        }
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(cusList)) {
            for (CusUserAddress cusUserAddress : cusList) {
                CountryModel countryModel = new CountryModel(cusUserAddress.getCountry(), getCountryNameByCode(cusUserAddress.getCountry()));
                countries.add(countryModel);
            }
        }
        if (!CollectionUtils.isEmpty(countryList)) {
            countryList.forEach(country -> countries.add(new CountryModel(country.getFigureCode(), country.getName())));
        }
        return countries;
    }

    /**
     * 获取国家的map,二字码与名字组成的。Map<code,name>
     *
     * @return 返回的集合
     */
    @Override
    public Map<String, String> getCountryNamesMap() {
        List<CountryModel> countries = this.findCountries(null);
        Map<String, String> countryMap = new HashMap<>();
        for (CountryModel country : countries) {
            countryMap.put(country.getCode(), country.getName());
        }
        return countryMap;
    }

    @Override
    public String getCountryNameByCode(String code) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("language", language);
        pd.put("figureCode", code);
        CountryDto dto = (CountryDto) dao.findForObject("CountryMapper" + ".findCountryByCode", pd);
        if (!ObjectUtils.isEmpty(dto)) {
            return dto.getName();
        }
        return "";
    }

    @Override
    public ResultDto searchCity(String countryCode, String q, int pageIndex, int pageSize) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("q", q);
        pd.put("language", language);
        Pagination page = new Pagination();
        page.setCurrentPage(pageIndex);
        page.setPageSize(pageSize);
        pd.setPagination(page);
        List<AreaDto> list;
        if (LanguageCode.CN_UPPER.equalsIgnoreCase(countryCode)) {
            pd.put("level", 2);

            list = dao.findForList("AreaCNMapper" + ".findCityListPage", pd, AreaDto.class);
        } else {
            pd.put("countryCode", countryCode);
            list = dao.findForList("AreaMapper" + ".findCityListPage", pd, AreaDto.class);
        }
        List<AreaModel> areas = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(i -> areas.add(new AreaModel(i)));
        }
        QResultDto dto = new QResultDto();
        dto.setData(areas);
        dto.setPagination(pd.getPagination());
        return dto;
    }


    @Override
    public AreaDto findByAreaId(String areaId, String countryCode) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("id", areaId);
        pd.put("language", language);
        AreaDto dto = new AreaDto();
        if (countryCode != null && countryCode.length() > 0) {
            if (LanguageCode.CN_UPPER.equals(countryCode)) {
                dto = (AreaDto) dao.findForObject("AreaCNMapper" + ".findByAreaId", pd);
            } else {
                dto = (AreaDto) dao.findForObject("AreaMapper" + ".findByAreaId", pd);
            }
        }
        return dto;
    }

    @Override
    public List<AreaDto> findNameByIds(List<String> ids, String countryCode) {
        List<AreaDto> areaList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(ids)) {
            ParamData pd = new ParamData();
            pd.put("ids", ids);
            if (countryCode != null && countryCode.length() > 0) {
                if (LanguageCode.CN_UPPER.equals(countryCode)) {
                    areaList = dao.findForList("AreaCNMapper" + ".findNameByIds", pd, AreaDto.class);
                } else {
                    areaList = dao.findForList("AreaMapper" + ".findNameByIds", pd, AreaDto.class);
                }
            }

        }
        return areaList;
    }


    @Override
    public ResultDto findAreaByParentId(String countryCode, String parentId, String q, int pageIndex, int pageSize) {
        List<CityModel> list = new ArrayList<CityModel>();
        ParamData pd = new ParamData();
        String language = PrincipalUtils.getLocalLanguage();
        pd.put("q", q);
        pd.put("language", language);
        Pagination page = new Pagination();
        page.setCurrentPage(pageIndex);
        page.setPageSize(pageSize);
        pd.setPagination(page);
        QResultDto dto = new QResultDto();
        if (countryCode == null) {
            pd.put("parentId", parentId);
            list = dao.findForList("AreaMapper" + ".findForeignAreaByParentIdListPage", pd, CityModel.class);
        } else {
            if (!LanguageCode.CN_UPPER.equals(countryCode)) {
                pd.put("parentId", parentId);
                list = dao.findForList("AreaMapper" + ".findForeignAreaByParentIdListPage", pd, CityModel.class);
            }
        }
        dto.setData(list);
        dto.setPagination(page);
        return dto;
    }

    @Override
    public List<AreaDto> findAreaNameByParentId(String countryCode, String parentId, String q, int pageIndex, int pageSize) {
        List<AreaDto> list = new ArrayList<>();
        ParamData pd = new ParamData();
        String language = PrincipalUtils.getLocalLanguage();
        pd.put("q", q);
        pd.put("language", language);
        Pagination page = new Pagination();
        page.setCurrentPage(pageIndex);
        page.setPageSize(pageSize);
        pd.setPagination(page);
        if (LanguageCode.CN_UPPER.equals(countryCode)) {
            pd.put("parentId", parentId);
            list = dao.findForList("AreaCNMapper" + ".findAreaListPage", pd, AreaDto.class);
        } else {
            if (!LanguageCode.CN_UPPER.equals(countryCode)) {
                pd.put("parentId", parentId);
                list = dao.findForList("AreaMapper" + ".findAreaListPage", pd, AreaDto.class);
            }
        }
        return list;
    }

    @Override
    public void fillCommonAreaNames(CommonAreaList commonAreaList) {
        if (!CollectionUtils.isEmpty(commonAreaList)) {
            //1、获取国家、国内地区、国外地区对应的map数据
            Map<String, String> countryMap = this.getCountryNamesMap();//国家——id与name对应的map
            Map<String, String> cnAreaMap = this.findCnAreaMapByIds(commonAreaList.findCnAreas());//国内地区-id与name对应的map
            Map<String, String> outCnAreaMap = this.getForeignAreaNamesByIds(commonAreaList.findOutCnAreas()); //国外地区-id与name对应的map

            //2、对单条数据进行name的填充，注意：这里填充的不是全路径
            for (CountryArea item : commonAreaList) {
                switch (item.getType()) {
                    case 1://国家
                        item.setName(countryMap.get(item.getCountryCode()));
                        break;
                    case 2://中国地区
                        item.setName(cnAreaMap.get(item.getAreaId()));
                        break;
                    case 3://国外地区
                        item.setName(outCnAreaMap.get(item.getAreaId()));
                        break;
                    case 4://邮编
                    default:
                        //TODO
                }
            }
        }
    }

    @Override
    public void fillAllPathCommonAreaNames(CommonAreaList commonAreaList) {
        if (!CollectionUtils.isEmpty(commonAreaList)) {
            //1、获取国家、中国地区对应的map数据
            Map<String, String> countryMap = this.getCountryNamesMap();//获取国家对应的map
            Map<String, String> outCnAreaMap = this.getForeignAreaNamesByIds(commonAreaList.findOutCnAreas()); //国外地区的id与name对应的map

            //2、对详情数据添加name与code全路径
            List<String> cnAreaIdList = new ArrayList<>();
            for (CountryArea countryArea : commonAreaList) {
                switch (countryArea.getType()) {
                    case 1://国家
                        countryArea.setName(countryMap.get(countryArea.getCountryCode()) == null ? countryArea.getCountryCode() : countryMap.get(countryArea.getCountryCode()));
                        countryArea.setCountryCode(countryArea.getCountryCode());
                        break;
                    case 2://中国地区
                        cnAreaIdList.add(countryArea.getAreaId());
                        break;
                    case 3://国外地区
                        countryArea.setName(countryMap.get(countryArea.getCountryCode()) + STRING_SPLIT + outCnAreaMap.get(countryArea.getAreaId()));
                        countryArea.setCountryCode(countryArea.getCountryCode() + STRING_SPLIT + countryArea.getAreaId());
                        break;
                    default:
                        break;
                }
            }

            //3、对中国地区全路径获取
            List<CountryArea> countryAreaList = this.getCnAreaAllPath(cnAreaIdList);
            Map<String, CountryArea> countryAreaMap = EntityUtils.getStringKeyMapFromBeans(countryAreaList, "areaId");

            //4、对中国地区全路径做填充
            commonAreaList.forEach(item -> {
                if (item.getType() == RegionConstants.Type.CHINA_REGION ) {
                    CountryArea countryArea = countryAreaMap.get(item.getAreaId());
                    if (!ObjectUtils.isEmpty(countryArea)) {
                        item.setCountryCode(countryArea.getCountryCode());
                        item.setName(countryArea.getName());
                    }
                }

            });
        }
    }

    /**
     * 处理模糊查询的地点，并将查询出来的国家和地区的id <br>
     * 设置到pd中,key为countries，areaIds
     *
     * @param pd pd 参数
     * @param q  q 模糊查询的关键字
     */
    @Override
    public void handlerQueryParam(Map<String, Object> pd, String q) {
        if (org.springframework.util.StringUtils.hasLength(q)) {
            //if (isContainChinese(q) || (!isContainChinese(q) && q.length() >= 3)) { //不包含汉字并且长度>=3的情况下执行
            List<String> areaIds = new ArrayList<>();
            List<String> countryCodes = new ArrayList<>();
            //国
            List<CountryModel> countries = this.findCountries(q);
            countryCodes.addAll(countries.stream().map(CountryModel::getCode).collect(Collectors.toList()));
            if (countryCodes.contains(LanguageCode.CN_UPPER)) {
                //所有省
                List<AreaModel> areaDtos = this.findArea(LanguageCode.CN_UPPER, 1, null);
                areaIds.addAll(areaDtos.stream().map(AreaModel::getId).collect(Collectors.toList()));
                //所有市
                areaDtos = this.findArea(LanguageCode.CN_UPPER, 2, null);
                areaIds.addAll(areaDtos.stream().map(AreaModel::getId).collect(Collectors.toList()));
            }

            //省
            List<AreaModel> areaCnDtos = findArea(LanguageCode.CN_UPPER, 1, q);
            if (!CollectionUtils.isEmpty(areaCnDtos)) {
                areaIds.addAll(areaCnDtos.stream().map(AreaModel::getId).collect(Collectors.toList()));
                List<String> provinceIds = new ArrayList<>();
                provinceIds.addAll(areaCnDtos.stream().filter(item -> item.getLevel() == 1).map(AreaModel::getId).collect(Collectors.toList()));
                //市
                if (!CollectionUtils.isEmpty(provinceIds)) {
                    ParamData pdCnCity = new ParamData();
                    pdCnCity.put("ids", provinceIds);
                    List<AreaCN> cnCityList = dao.findForList("AreaCNMapper" + ".findByParentIds", pdCnCity, AreaCN.class);
                    areaIds.addAll(cnCityList.stream().map(AreaCN::getId).collect(Collectors.toList()));
                }
            }

            //普通地方
            areaCnDtos = findArea(LanguageCode.CN_UPPER, 0, q);
            if (!CollectionUtils.isEmpty(areaCnDtos)) {
                areaIds.addAll(areaCnDtos.stream().map(AreaModel::getId).collect(Collectors.toList()));
            }


            //国外二级城市
            if (!CollectionUtils.isEmpty(countryCodes)) {
                ParamData pdCity = new ParamData();
                pdCity.put("parentIds", countryCodes);
                List<AreaDto> areaCityDtos = dao.findForList("AreaMapper" + ".findCityIdsByParentIds", pdCity, AreaDto.class);
                if (!CollectionUtils.isEmpty(areaCityDtos)) {
                    areaIds.addAll(areaCityDtos.stream().map(AreaDto::getId).collect(Collectors.toList()));
                }
            }

            //国外普通地方
            List<AreaModel> areaDtos = findArea(null, 0, q);
            areaIds.addAll(areaDtos.stream().map(AreaModel::getId).collect(Collectors.toList()));


            //如果查到的太多  则不以此条件查询
            if (areaIds.size() > MAX_SIZE) {
                areaIds.clear();
            }

            if (areaIds.size() > 0) {
                pd.put("areaIds", areaIds);
            }
            if (!CollectionUtils.isEmpty(countryCodes)) {
                pd.put("countries", countryCodes);
            }
            //}
        }
    }

    @Override
    protected String getMapperNamespace() {
        // TODO Auto-generated method stub
        return null;
    }

    private boolean isContainChinese(String str) {
        Pattern p = Pattern.compile(CHINESE);
        Matcher m = p.matcher(str);
        return m.find();
    }

    /**
     * 通过给字的地区节点与二字码得到相应的全路径集
     *
     * @param cnAreaIdList 　要得到全路径的子节点集合
     * @return　得到的路径集合
     */
    private List<CountryArea> getCnAreaAllPath(List<String> cnAreaIdList) {
        List<CountryArea> countryAreaList = new ArrayList<>();
        for (String cnAreaId : cnAreaIdList) {
            List<CodeNameDto> cnAreaList = new ArrayList<>();
            recursivePath(cnAreaId, cnAreaList);
            if (CollectionUtils.isEmpty(cnAreaList)) {
                continue;
            }
            Collections.reverse(cnAreaList);//旋转

            StringBuilder countryCodePath = new StringBuilder();
            StringBuilder countryNamePath = new StringBuilder();
            for (CodeNameDto dto : cnAreaList) {
                countryCodePath.append(dto.getCode()).append(STRING_SPLIT);
                countryNamePath.append(dto.getName()).append(STRING_SPLIT);
            }

            CountryArea countryArea = new CountryArea();
            countryArea.setAreaId(cnAreaId);
            countryArea.setCountryCode("CN/" + countryCodePath.substring(0, countryCodePath.length() - 1));
            countryArea.setName("中国/" + countryNamePath.substring(0, countryNamePath.length() - 1));
            countryAreaList.add(countryArea);
        }
        return countryAreaList;
    }

    /**
     * 递归通过子节点得到父节点
     *
     * @param areaId   　子节点id
     * @param areaPath 　得到的集合
     */
    private void recursivePath(String areaId, List<CodeNameDto> areaPath) {
        TreeNodeDto node = this.findCNAreaById(areaId);
        if (node != null) {
            areaPath.add(node);
            if (!ROOT.equals(node.getParent())) {
                recursivePath(node.getParent(), areaPath);
            }
        }
    }

    /**
     * 判断要保存的dto数据与已保存的分区item数据是否有重复
     *
     * @param dtoCountryAreaList  要保存的地区数据
     * @param dataCountryAreaList 已保存的地区数据
     */
    @Override
    public void judgeArea(List<CountryArea> dtoCountryAreaList, List<CountryArea> dataCountryAreaList) {
        this.validaArea(dtoCountryAreaList);//1、校验前端传递过来的地区的有效性
        this.isExistArea(dtoCountryAreaList, dataCountryAreaList);
    }

    @Override
    public void judgePostcode(List<Postcode> dtoPostcodeList, List<Postcode> dataPostcodeList) {
        if (!CollectionUtils.isEmpty(dtoPostcodeList)) {
            Set<Postcode> postcodes = this.validPostcode(dtoPostcodeList);//1、校验前端传递过来的邮编的有效性,因为要给前端返回一个集合，所以这里用集合统一处理
            for (Postcode dtoPostcode : dtoPostcodeList) { //前端传过来的postcode与后端数据库重复判断
                int count = Collections.frequency(dataPostcodeList, dtoPostcode);
                if (count >= 1) { //如果数据库中有一个代表已经重复，所以这里用等于1
                    postcodes.add(dtoPostcode);
                }
            }
            if (!CollectionUtils.isEmpty(postcodes)) {
                throw Exceptions.bizExceptionData(ErrorCodes.ERROR_COMMON, postcodes, "要保存的邮编有重复！");
            }
        }
    }

    @Override
    public void setCountryArea(String countryCode, CommonAreaEntity entry) {
        if (!countryCode.contains(STRING_SPLIT)) { //国家
            entry.setType(1);
            entry.setCountry(countryCode);
        } else if (countryCode.toUpperCase().contains(LanguageCode.CN_UPPER) && countryCode.contains(STRING_SPLIT)) { //中国地区
            entry.setType(2);
            entry.setCountry(countryCode.split(STRING_SPLIT)[0]);//第一位存的国家
            entry.setAreaId(countryCode.split(STRING_SPLIT)[countryCode.split(STRING_SPLIT).length - 1]);//最后一位存要保存的地区id

        } else { //国外地区
            entry.setType(3);
            entry.setCountry(countryCode.split(STRING_SPLIT)[0]);//第一位存的国家
            entry.setAreaId(countryCode.split(STRING_SPLIT)[countryCode.split(STRING_SPLIT).length - 1]);//最后一位存要保存的地区id
        }
    }

    /**
     * 校验前端传过来的邮编集合是否有重复
     *
     * @param postcodeList 邮编集合
     * @return 重复的邮编数据
     */
    private Set<Postcode> validPostcode(List<Postcode> postcodeList) {
        Set<Postcode> postcodes = new HashSet<>();
        for (Postcode postcode : postcodeList) {
            if (!StringUtils.hasLength(postcode.getCountry()) || !StringUtils.hasLength(postcode.getStartPostcode()) || !StringUtils.hasLength(postcode.getEndPostcode())) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要保存的邮编包含空！");
            }
            int count = Collections.frequency(postcodeList, postcode);
            if (count > 1) {
                postcodes.add(postcode);
            }
        }
        return postcodes;
    }


    /**
     * 根据中国地区的id集合（cnAreaIds）获取其对应的map(id,name)
     *
     * @param cnAreaIds 中国地区的id集合,可以传空，这样就可以得到所有的数据集合
     * @return 获取到的id，name对应的map集合
     */
    private Map<String, String> findCnAreaMapByIds(List<String> cnAreaIds) {
        Map<String, String> cnAreaMap = new HashMap<>();
        if (cnAreaIds != null && cnAreaIds.size() > 0) {
            List<TreeNodeDto> areaList = this.findCnAreaByIds(cnAreaIds);
            for (TreeNodeDto areaCn : areaList) {
                cnAreaMap.put(areaCn.getCode(), areaCn.getName());
            }
        }
        return cnAreaMap;
    }

    /**
     * 根据中国地区的id集合（cnAreaIds）获取其对应的数据，仅包含（id，name），别的字段为Null
     *
     * @param cnAreaIds 要查询的中国地区id集合
     * @return 查询到的数据集合
     */
    private List<TreeNodeDto> findCnAreaByIds(List<String> cnAreaIds) {
        List<TreeNodeDto> treeNodeDtoList = new ArrayList<>();
        if (cnAreaIds != null && cnAreaIds.size() > 0) {
            ParamData pd = new ParamData();
            pd.put("ids", cnAreaIds);
            List<AreaCN> areaCnList = dao.findForList("AreaCNMapper" + ".findCnAreaByIds", pd, AreaCN.class);

            if (!CollectionUtils.isEmpty(areaCnList)) {
                areaCnList.forEach(treeNodeDto -> treeNodeDtoList.add(
                        new TreeNodeDto(treeNodeDto.getId(), treeNodeDto.getName(), treeNodeDto.getParentId())));
            }
        }
        return treeNodeDtoList;
    }

    private TreeNodeDto findCNAreaById(String areaId) {
        if (areaId != null && areaId.length() > 0) {
            List<String> cnAreaIds = new ArrayList<>();
            cnAreaIds.add(areaId);
            List<TreeNodeDto> list = findCnAreaByIds(cnAreaIds);
            if (list != null && list.size() > 0) {
                return list.get(0);
            }
        }
        return null;
    }

    /**
     * 根据国外地区的id集合（outCnAreaIds）查询其id与name对应的map
     *
     * @param outCnAreaIds 国外地区的id集合
     * @return 查询出的map数据集合
     */
    private Map<String, String> getForeignAreaNamesByIds(List<String> outCnAreaIds) {
        Map<String, String> outCnAreaMap = new HashMap<>();//国外地区map
        List<Area> areaList = this.getForeignAreaByIds(outCnAreaIds);
        if (!CollectionUtils.isEmpty(areaList)) {
            areaList.forEach(area -> outCnAreaMap.put(area.getId(), area.getName()));
        }
        return outCnAreaMap;
    }

    /**
     * 根据国外地区的id集合（outCnAreaIds）查询其对应的实体集合,包含id,name，别的字段为NULL
     *
     * @param foreignAreaIds 国外地区的id集合
     * @return 查询出的数据集合
     */
    private List<Area> getForeignAreaByIds(List<String> foreignAreaIds) {
        List<Area> areaList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(foreignAreaIds)) {
            ParamData pd = new ParamData();
            pd.put("outCnAreaIds", foreignAreaIds);
            areaList = dao.findForList("AreaMapper" + ".findOutCnAreasByIds", pd, Area.class);
        }
        return areaList;
    }


    /**
     * @param areaId
     * @return
     */
    private String getCNAreaName(String areaId) {
        AreaDto area = findByAreaId(areaId, LanguageCode.CN_UPPER);
        if (area != null) {
            return area.getName();
        }
        return "";
    }

    private String getForeignAreaName(String outCnAreaId) {
        String name = "";
        if (StringUtils.hasLength(outCnAreaId)) {
            List<Area> areas = this.getForeignAreaByIds(Arrays.asList(outCnAreaId));
            if (!CollectionUtils.isEmpty(areas)) {
                Area area = areas.get(0);
                name = area.getName();
            }
        }
        return name;
    }


    private List<AreaModel> findArea(String countryCode, int level, String q) {
        String language = PrincipalUtils.getLocalLanguage();
        ParamData pd = new ParamData();
        pd.put("q", q);
        pd.put("language", language);
        List<AreaDto> list;
        if (LanguageCode.CN_UPPER.equalsIgnoreCase(countryCode)) {
            if (level > 0) {
                pd.put("level", level);
            }
            list = dao.findForList("AreaCNMapper" + ".findCity", pd, AreaDto.class);
        } else {
            pd.put("countryCode", countryCode);
            list = dao.findForList("AreaMapper" + ".findCityIds", pd, AreaDto.class);
        }
        List<AreaModel> areas = new ArrayList<>();
        if (list != null && list.size() > 0) {
            list.forEach(i -> areas.add(new AreaModel(i)));
        }
        return areas;
    }


    /**
     * 判断前端传递过来的中国地区与国外地区数据是否是有效的
     *
     * @param countryAreaList 前端传递过来的国家地区灵气集合
     */
    private void validaArea(List<CountryArea> countryAreaList) {

        List<CountryArea> dtoCnAreaAllPathList = new ArrayList<>();//前端传过来的,中国地区的全路径数据
        List<String> dtoCnAreaLastList = new ArrayList<>();//前端传过来的，中国地区通过最后一位，用于从数据库拼装
        List<CountryArea> dtoCnAreaAllPathAssembleList = new ArrayList<>();//前端传过来的，从数据库进行拼装的全路径
        List<String> dtoOutCnAreaLastAreaList = new ArrayList<>();//前端传递过来的，国外最后一个地域的数据集合

        for (CountryArea countryArea : countryAreaList) {
            String area = countryArea.getCountryCode();//前端传递的地区的全路径（包含国内与国外）
            if (area.contains(STRING_SPLIT)) { //如果数据包含STRING_SPLIT代表是的是地区，而不是国家
                if (area.toUpperCase().contains(LanguageCode.CN_UPPER)) {//代表中国地区
                    dtoCnAreaAllPathList.add(countryArea);
                    dtoCnAreaLastList.add(splitLastStr(area));
                } else { //国外地区
                    dtoOutCnAreaLastAreaList.add(splitLastStr(area));//取出最后一位
                }
            }
        }
        //根据前端传过来的中国地区最后一位，从数据库中重新拼装数据
        if (!CollectionUtils.isEmpty(dtoCnAreaLastList)) {
            dtoCnAreaAllPathAssembleList = getCnAreaAllPath(dtoCnAreaLastList);
        }

        //如果前端传递过来的中国地区全路径与数据库拼出来的中国地区全路径不能完全一样，代表前端传递过来的数据格式有问题
        if (dtoCnAreaAllPathList.size() > 0 && !(dtoCnAreaAllPathList.containsAll(dtoCnAreaAllPathAssembleList) && dtoCnAreaAllPathList.size() == dtoCnAreaAllPathAssembleList.size())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "中国地区的数据有误！");
        }

        //国外地区数据有效性校验
        List<Area> areaList = this.getForeignAreaByIds(dtoOutCnAreaLastAreaList);
        //如果查询出来的国外地区的数据集与要查询的个数不一样，代表前端传递过来的部分数据在数据库里并不存在
        if (areaList.size() != dtoOutCnAreaLastAreaList.size()) {
            throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "国外地区数据有误！");
        }
    }

    /**
     * 判断已经保存的地区与要保存的地区是否有重复
     *
     * @param dtoCountryAreaList  将要保存的地区数据
     * @param dataCountryAreaList 已经保存的地区数据
     */
    private void isExistArea(List<CountryArea> dtoCountryAreaList, List<CountryArea> dataCountryAreaList) {
        List<CountryArea> countryAreaList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(dataCountryAreaList)) {
            countryAreaList.addAll(dataCountryAreaList);
        }
        countryAreaList.addAll(dtoCountryAreaList);

        //判断重复
        if (!CollectionUtils.isEmpty(dtoCountryAreaList) && !CollectionUtils.isEmpty(dataCountryAreaList)) {
            for (CountryArea dtoCountryArea : dtoCountryAreaList) {
                for (CountryArea area : dataCountryAreaList) {
                    if (dtoCountryArea.getCountryCode().contains(area.getCountryCode())
                            || area.getCountryCode().contains(dtoCountryArea.getCountryCode())) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要保存的地区有重复！");
                    }
                }

            }
        }

        for (CountryArea countryArea : countryAreaList) {
            int count = Collections.frequency(countryAreaList, countryArea);
            if (count > 1) {
                throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "要保存的地区有重复！");
            }
        }
    }


    @Override
    public void setAddressModel(AddressModel addressModel) {
        if (!ObjectUtils.isEmpty(addressModel)) {
            //当地址中存有海运与空运的工具id时，需要从数据库中取出地址与运输id的名字
            if (addressModel.getTransportId() > 0) {
                if (addressModel.getTransportType() == CommCodes.TRANSPORT_SEA) {
                    this.clearData(addressModel);
                    Port port = portService.findShortById(addressModel.getTransportId());
                    if (ObjectUtils.isEmpty(port)) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "未找到相应的海运地址，请核查！");
                    }
                    addressModel.setTransportName(port.getName());
                    addressModel.setCountryCode(port.getCountryId());
                    addressModel.setCityId(port.getCityId());
                    addressModel.setAddress(port.getAddress());
                    addressModel.setTransportEnglishName(port.getEnglishName());


                } else if (addressModel.getTransportType() == CommCodes.TRANSPORT_AIR) {
                    this.clearData(addressModel);
                    Airport airport = airportService.findShortById(addressModel.getTransportId());
                    if (ObjectUtils.isEmpty(airport)) {
                        throw Exceptions.bizException(ErrorCodes.ERROR_COMMON, "未找到相应的空运地址，请核查！");
                    }
                    addressModel.setTransportName(airport.getName());
                    addressModel.setCountryCode(airport.getCountryId());
                    addressModel.setCityId(airport.getCityId());
                    addressModel.setAddress(airport.getAddress());
                }
            }

            Map<String, String> countryMap = this.getCountryNamesMap();
            addressModel.setCountryName(countryMap.get(addressModel.getCountryCode()));
            if (LanguageCode.CN_UPPER.equalsIgnoreCase(addressModel.getCountryCode())) {
                addressModel.setProvinceName(this.getCNAreaName(addressModel.getProvinceId()));
                addressModel.setCityName(this.getCNAreaName(addressModel.getCityId()));
                addressModel.setStreetName(this.getCNAreaName(addressModel.getStreetId()));
                addressModel.setDistrictName(this.getCNAreaName(addressModel.getDistrictId()));
            } else {
                addressModel.setCityName(this.getForeignAreaName(addressModel.getCityId()));
            }
        }
    }

    private void clearData(AddressModel addressModel) {
        addressModel.setTransportName(null);
        addressModel.setCityId(null);
        addressModel.setAddress(null);
        addressModel.setCountryCode(null);
        addressModel.setCityName(null);
        addressModel.setCountryName(null);
        addressModel.setDistrictName(null);
        addressModel.setDistrictId(null);
        addressModel.setProvinceId(null);
        addressModel.setProvinceName(null);
        addressModel.setStreetId(null);
        addressModel.setStreetName(null);
    }


    private String splitLastStr(String str) {
        return str.split(STRING_SPLIT)[str.split(STRING_SPLIT).length - 1];
    }

}
